Golang 命令行程序之 cobra 包
Cobra 是什么?
Cobra 既是一个用于创建强大的现代 CLI 应用程序的库,也是一个用于生成应用程序和命令文件的程序。
cobra 中的主要概念
cobra 中有个重要的概念,分别是 commands、arguments 和 flags。其中 commands 代表行为,arguments 就是命令行参数(或者称为位置参数),flags 代表对行为的改变(也就是我们常说的命令行选项)。执行命令行程序时的一般格式为:
APPNAME COMMAND ARG --FLAG
比如下面的例子
# server是 commands,port 是 flag
hugo server --port=1313
# clone 是 commands,URL 是 arguments,brae 是 flag
git clone URL --bare
快速使用
首先安装 cobra 库
go get -u github.com/spf13/cobra
go get -u github.com/spf13/viper
然后就可以用 cobra 程序生成应用程序框架了:
cobra init [name] --pkg-name [pkgname]
# example
# 创建在当前目录下面
cobra init stcobra --pkg-name alsritter.icu/stcobra
此时的程序并没有什么功能,执行它只会输出一些默认的提示信息:
A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.
使用 cobra 程序生成命令代码
除了生成应用程序框架,还可以通过 cobra add 命令生成子命令的代码文件,比如下面的命令会添加两个子命令 image 和 container 相关的代码文件(当项目目录下):
go install github.com/spf13/cobra-cli@latest
使用
cobra-cli add image
cobra-cli add container
它就会被添加到项目里面了
这两条命令分别生成了 stcobra 程序中 image 和 container 子命令的代码,当然了,具体的功能还得靠我们自己实现。
为命令添加具体的功能
到目前为止,我们一共为 stcobra 程序添加了三个 Command,分别是 rootCmd(cobra init 命令默认生成)、imageCmd 和 containerCmd。
打开文件 root.go ,找到变量 rootCmd 的初始化过程并为之设置 Run 方法:
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("执行了 root 命令")
},
再次执行,不带参数就是输出
执行了 root 命令
再为这个应用添加一个 version 命令
cobra-cli add version
添加参数配置
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of stcobra",
Long: `All software has versions. This is stcobra's`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("stcobra version is v1.0")
},
}
为 Command 添加选项(flags)
选项(flags)用来控制 Command 的具体行为。根据选项的作用范围,可以把选项分为两类:
- persistent
- local
对于 persistent 类型的选项,既可以设置给该 Command,又可以设置给该 Command 的子 Command。
示例:
对于一些全局性的选项,比较适合设置为 persistent 类型,比如控制输出的 verbose 选项:
var Verbose bool
func init() {
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
}
local 类型的选项只能设置给指定的 Command,比如下面定义的 source 选项(该选项不能指定给 rootCmd 之外的其它 Command):
var Source string
rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
默认情况下的选项都是可选的,但一些用例要求用户必须设置某些选项,这种情况 cobra 也是支持的,通过 Command 的 MarkFlagRequired 方法标记该选项即可:
var Name string
rootCmd.Flags().StringVarP(&Name, "name", "n", "", "user name (required)")
rootCmd.MarkFlagRequired("name")
命令行参数(arguments) 校验
cobra 默认提供了一些验证方法:
- NoArgs - 如果存在任何位置参数,该命令将报错
- ArbitraryArgs - 该命令会接受任何位置参数
- OnlyValidArgs - 如果有任何位置参数不在命令的 ValidArgs 字段中,该命令将报错
- MinimumNArgs(int) - 至少要有 N 个位置参数,否则报错
- MaximumNArgs(int) - 如果位置参数超过 N 个将报错
- ExactArgs(int) - 必须有 N 个位置参数,否则报错
- ExactValidArgs(int) 必须有 N 个位置参数,且都在命令的 ValidArgs 字段中,否则报错
- RangeArgs(min, max) - 如果位置参数的个数不在区间 min 和 max 之中,报错
也可以自定义这个校验
var cmd = &cobra.Command{
Short: "hello",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("requires a color argument")
}
if myapp.IsValidColor(args[0]) {
return nil
}
return fmt.Errorf("invalid color specified: %s", args[0])
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, World!")
},
}
比如要让 Command cmdTimes 至少有一个位置参数,可以这样初始化它:
var cmdTimes = &cobra.Command{
Use: …
Short: …
Long: …
Args: cobra.MinimumNArgs(1),
Run: …
}
执行的各个阶段
Command 执行的操作是通过 Command.Run 方法实现的,为了支持我们在 Run 方法执行的前后执行一些其它的操作,Command 还提供了额外的几个方法,它们的执行顺序如下:
var rootCmd = &cobra.Command{
Use: "stcobra",
Short: "sparkdev's cobra demo",
Long: "the demo show how to use cobra package",
// 子命令会继承这个函数
PersistentPreRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
},
PreRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("cobra demo program, with args: %v\n", args)
},
PostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
},
// 子命令会继承这个函数
PersistentPostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
},
}